package core;

import java.awt.geom.Rectangle2D;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.List;
import java.util.Set;

import util.Constants;
import util.TimeUtil;

/**
 * Entry Class to compare performance of TIMS and parinet<br>
 * Junction implementation
 * 
 * @author Xiaohui
 * @version 0.1 read from programatic parameters
 * @version 0.2 read from conf file; remove Constants
 */

public class Driving implements Constants {
	// need to change for every dataset
	static int indexNet = 0; // decide if to index network
	static int indexRawData = 0; // decide if to index raw data by id
	static String queryFile = pathPrefix + "queries/query_test.txt";
	static String dataFile = pathPrefix + "dataset/old50_100_15.txt";
	static String sys = "linux"; // linux or windows
	static int gridDim = 4;
	static int prog = 1; // 1: tims; 2: parinet 3: timsv2
	static double sportion = 0.01; // spatial portion
	static double tportion = 0.01; // temporal portion
	static int totalTimeLength = 1000;
	static int TimsIndexRawData = 1; // 0: no; 1: yes
	static int parinetIndexRawData = 0; // 0: no; 1: yes

	static List<QueryParser> qparsers;

	static RawDataIndex rawIndexer = new RawDataIndex(
			Constants.rawTreeFileById, Constants.rawBlockFileById);

	public static void main(String[] args) throws Exception {
		// rawIndexer.indexNBGFileById(datafile);
		String usage = "java -jar -Xms512m -Xmx512m TIMS.jar conf_file";
		if (args.length != 1) {
			System.err.println(usage);
			System.exit(0);
		}
		readConf(args[0]);
		qparsers = QueryFileReader.getParsers(queryFile);

		if (indexNet != 0) {
			indexNetwork();
		}
		if (indexRawData != 0) {
			indexRawData();
		}

		if (prog == 1) {
			startTims();
		} else if (prog == 2) {
			startParinet();
		} else if (prog == 3) {
			startTimsv2();
		} else if (prog == 4) {
			System.out.println("==========Query Generator========");
			genQuery();
		} else {
			System.err.println("Wrong conf file!");
		}
		// System.out.println("query file:" + queryFile);
		//		
		// System.out.println("qparsers size: " + qparsers.size());
	}

	static void genQuery() throws Exception {
		QueryGen.genQueryFileForOlden(sportion, tportion, totalTimeLength,
				queryFile);
	}

	static void readConf(String confFile) {
		BufferedReader in;
		try {
			in = new BufferedReader(new FileReader(confFile));
			String line = in.readLine();
			// System.out.println(line);
			while (line.startsWith("#")) {
				line = in.readLine();
			}
			sys = line;
			// if (sys.equalsIgnoreCase("windows")) {
			// Constants.pathPrefix = "D:/Research/parinet/";
			// }
			queryFile = in.readLine();
			dataFile = in.readLine();

			prog = Integer.parseInt(in.readLine());
			if (prog == 2) {
				parinetIndexRawData = Integer.parseInt(in.readLine());
			} else if (prog == 3) {
				TimsIndexRawData = Integer.parseInt(in.readLine());
			}

			gridDim = Integer.parseInt(in.readLine());
			indexNet = Integer.parseInt(in.readLine());
			indexRawData = Integer.parseInt(in.readLine());
			sportion = Double.parseDouble(in.readLine());
			tportion = Double.parseDouble(in.readLine());
			totalTimeLength = Integer.parseInt(in.readLine());

			in.close();

			// print them out
			System.out.println("System: " + sys);
			System.out.println("quey file: " + queryFile);
			System.out.println("data file: " + dataFile);
			System.out.println("index network or not: " + indexNet);
			System.out.println("index raw data by id or not: " + indexRawData);
			System.out.println("grid dimension: " + gridDim);
			System.out.println("which prog to run: " + prog);
			System.out.println("Re-index or not: " + TimsIndexRawData);

		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * index raw data by id
	 * 
	 * @throws Exception
	 */
	static void indexRawData() throws Exception {
		RawDataIndex rawIndexer = new RawDataIndex(Constants.rawTreeFileById,
				Constants.rawBlockFileById);
		rawIndexer.indexNBGFileById(dataFile);
	}

	static void indexNetwork() throws Exception {
		RoadNetworkIndex netindexer = new RoadNetworkIndex();
		// B+tree index
		netindexer.indexRoadNetworkByEdgeId();

		// Rtree index
		String queryType = "intersection";
		netindexer.RTreeLoadEdge(Constants.brNetEdgeFile,
				Constants.brNetRTreeFile, Constants.rTreeCapacity, queryType);
	}

	static void startParinet() throws Exception {
		System.out.println("=======PARINET================");
		// ============Constants and objects ==========================
		Parinet parinet = new Parinet();
		RawDataIndex rawidxer = new RawDataIndex(rawTreeFileById,
				rawBlockFileById);
		// ============Load data===================
		if (parinetIndexRawData == 1) {
			parinet.buildPartitions();
			parinet.loadData(dataFile);
		} else {
			parinet.reOpenPartitions();
		}
		int queryCount = 0;
		long start = System.currentTimeMillis();
		int ansSetSize = 0;
		// ============Query Processing===================
		System.out.println("qparser size: " + qparsers.size());
		for (QueryParser qparser : qparsers) {
			System.out.println("=============Query " + (queryCount++)
					+ "=========");
			Set<Partition> partitionNumbers = parinet.doSpatialFiltering(
					Constants.intersection, Constants.brNetRTreeFile, qparser);
			Set<Integer> objidSet = parinet.doTemporalFilter(qparser,
					partitionNumbers);
			Set<Integer> result = Matching.doExactMatch(objidSet, rawidxer,
					qparser);
			System.out.println("result size: " + result.size() + "=" + result);
			ansSetSize += result.size();
		}
		long end = System.currentTimeMillis();

		// ===========Print statistics============
		System.out.println("Average time(ms): "
				+ TimeUtil.getAvgTimeInMs(start, end, queryCount));
		System.out.println("AVG query result size: " + (double) ansSetSize
				/ queryCount);
	}

	/**
	 * This method does part of indexing in parinet system.<br>
	 * Assuming the network is already indexed with R-tree.
	 */
	static void startParinetV2Indexing(ParinetV2 pv2) throws Exception {
		String separateFileFolder = pathPrefix + "medium/";
		String sqlFile = pathPrefix
		+ "medium/parinet_sql";
		// 1. separate raw data file into files and generate sql scripts
		pv2.separateIntoFiles(dataFile,separateFileFolder ,sqlFile );
		// 2. load scripts into mysql. Scripts do three things
		// create tables + index each table's curr_time with BTree + load data
		pv2.executeSQLFile(sqlFile);
	}

	static void startParinetV2QueryProcessing(ParinetV2 pv2) throws Exception {
		// 1. do spatial filter to get partition thus table name
		// 2. query each table
		System.out.println("=======PARINETV2================");
		int queryCount = 0;
		long start = System.currentTimeMillis();
		int ansSetSize = 0;
		// ============Query Processing===================
		System.out.println("qparser size: " + qparsers.size());
		for (QueryParser qparser : qparsers) {
			System.out.println("=============Query " + (queryCount++)
					+ "=========");
			Set<Rectangle2D> partitionNumbers = pv2.doSpatialFiltering(
					Constants.intersection, Constants.brNetRTreeFile, qparser);
			// temporal filtering is replaced by
			// Set<Integer> objidSet = pv2.doTemporalFilter(qparser,
			// partitionNumbers);

			// Set<Integer> result = Matching.doExactMatch(objidSet, rawidxer,
			// qparser);
			// System.out.println("result size: " + result.size() + "=" +
			// result);
			// ansSetSize += result.size();
		}
		long end = System.currentTimeMillis();

	}

	static void startTims() throws Exception {
		RawDataIndex rawidxer = new RawDataIndex(rawTreeFileById,
				rawBlockFileById);// indexed file is defined in its class

		TimsQPV1 qs = new TimsQPV1(queryFile, Constants.CPRTreeFile,
				Constants.intersection);

		if (indexRawData == 1) {
			qs.loadRawData(dataFile);
		}
		// ============Query Processing===================
		int queryCount = 0;
		int ansSetSize = 0;
		// ============Query Processing===================
		long start = System.currentTimeMillis();
		for (QueryParser parser : qparsers) {
			System.out.println("=============Query " + (queryCount++)
					+ "=========");

			// Set<Integer> oidset = indexer.QueryProcessingEdgeImpl(parser,
			// Constants.intersection, Constants.networkRTreeFile,
			// netIndexer);

			qs.doSpatialFilterWithExtension(parser);
			// Set<Integer> oidset = qs.doTemporalFilterBTree();
			Set<Integer> oidset = qs.doTemporalFilterByScanning(parser
					.getStartTime(), parser.getEndTime());

			Set<Integer> exactOidset = Matching.doExactMatch(oidset, rawidxer,
					parser);
			System.out.println("result size: " + exactOidset.size() + "="
					+ exactOidset);
			ansSetSize += exactOidset.size();
		}

		long end = System.currentTimeMillis();
		// ===========Print statistics============
		System.out.println("Average time(ms): "
				+ TimeUtil.getAvgTimeInMs(start, end, queryCount));
		System.out.println("AVG query result size: " + (double) ansSetSize
				/ queryCount);
	}

	static void startTimsv2() throws Exception {
		System.out.println("======TIMS2=====");
		TimsQPV2 qs = new TimsQPV2();
		RawDataIndex rawDataById = new RawDataIndex(Constants.rawTreeFileById,
				Constants.rawBlockFileById);// indexed file is defined in its
		// class

		if (TimsIndexRawData == 1) {
			qs.loadRawDataBTree(dataFile); // index raw data based on edge
			// id+time point
		}

		// ============Query Processing===================
		int queryCount = 0;
		int ansSetSize = 0;
		long start = System.currentTimeMillis();
		for (QueryParser parser : qparsers) {
			System.out.println("=============Query " + (queryCount++)
					+ "=========");
			Set<Long> eids = qs.doEdgeSpatialFilter(parser);
			Set<Integer> oidset = qs.doTemporalFilterBTree(parser, eids);
			Set<Integer> exactOidset = Matching.doExactMatch(oidset,
					rawDataById, parser);
			System.out.println("result size: " + exactOidset.size() + "="
					+ exactOidset);
			ansSetSize += exactOidset.size();
		}
		long end = System.currentTimeMillis();
		// ===========Print statistics============
		System.out.println("Average time(ms): "
				+ TimeUtil.getAvgTimeInMs(start, end, queryCount));
		System.out.println("AVG query result size: " + (double) ansSetSize
				/ queryCount);
	}
}
